using Digitalmes.Domain.Entities.Mes.Masters;

namespace Digitalmes.Domain.Entities.Mes.Productions;

/// <summary>
/// 生产工单。
/// </summary>
/// <remarks>
/// <para>此处生产工单可进行拆分为多个子工单，子工单物料类型与父工单不同。</para>  
/// <para>若是自动生产中（来料零件码未绑定工单时），同一种产品在同一时刻应该只有一张工单处于准备或正在生产状态。</para>  
/// </remarks>
[SugarTable("prod_work_order")]
public sealed class ProdWorkOrder : AuditedEntity, ISoftDelete
{
    /// <summary>
    /// 父工单 Id。
    /// </summary>
    public long ParentId { get; set; }

    /// <summary>
    /// 工单编号
    /// </summary>
    [NotNull]
    public string? Wo { get; set; }

    /// <summary>
    /// 产品 Id。
    /// </summary>
    public long ProductId { get; set; }

    /// <summary>
    /// 产品
    /// </summary>
    [Navigate(NavigateType.OneToOne, nameof(ProductId))]
    public MdMaterial? Product { get; set; }

    /// <summary>
    /// 选择生产的产线 Id
    /// </summary>
    public long LineId { get; set; }

    /// <summary>
    /// 产线
    /// </summary>
    [Navigate(NavigateType.OneToOne, nameof(LineId))]
    public MdLine? Line { get; set; }

    /// <summary>
    /// 工单类型（试制、量产、返工）
    /// </summary>
    [SugarColumn(SqlParameterDbType = typeof(EnumToStringConvert))]
    public WoTypeEnum WoType { get; set; }

    /// <summary>
    /// 计划生产数量
    /// </summary>
    public int PlanQty { get; set; }

    /// <summary>
    /// 计划开始日期
    /// </summary>
    public DateTime PlanStartDate { get; set; }

    /// <summary>
    /// 计划完成日期
    /// </summary>
    public DateTime PlanEndDate { get; set; }

    /// <summary>
    /// 优先级，数值越小优先级越高， 0 表示不参与排序
    /// </summary>
    /// <remarks>
    /// 优先级唯一性主要对活跃工单（"暂停"、"进行中" 状态），
    /// 排产时设置优先级，完工（或关闭）时下会重置。
    /// </remarks>
    public int Priority { get; set; }

    /// <summary>
    /// 实际开始日期
    /// </summary>
    public DateTime? ActualStartDate { get; set; }

    /// <summary>
    /// 实际完成日期
    /// </summary>
    public DateTime? ActualEndDate { get; set; }

    /// <summary>
    /// 已投产的数量，表示已投入生产的数量。
    /// </summary>
    /// <remarks>
    /// 上线数量 >= 实际生产数量 + 报废数量；
    /// 当上线数量等于计划数量时，根据实际情况进行工单切换。
    /// </remarks>
    public int StartedQty { get; set; }

    /// <summary>
    /// 良品数量，表示生产完成的最终合格品数量。
    /// </summary>
    /// <remarks>OK下线产品都归于此数量。</remarks>
    public int GoodQty { get; set; }

    /// <summary>
    /// 报废数量。
    /// </summary>
    public int ScrappedQty { get; set; }

    /// <summary>
    /// 是否为主工单。
    /// </summary>
    /// <remarks>最终生产的成品属于主工单，主工单数据会加入到产能统计中。</remarks>
    public bool IsMaster { get; set; }

    /// <summary>
    /// 工单来源（手动导入、ERP下发）
    /// </summary>
    public string? Source { get; set; }

    /// <summary>
    /// 产成品批次号
    /// </summary>
    public string? BatchNo { get; set; }

    /// <summary>
    /// 描述
    /// </summary>
    public string? Remark { get; set; }

    /// <summary>
    /// 工单状态
    /// </summary>
    [SugarColumn(SqlParameterDbType = typeof(EnumToStringConvert))]
    public WoStatusEnum Status { get; set; }

    /// <summary>
    /// 上一状态。
    /// </summary>
    /// <remarks>仅系统内部可见，用于切换部分工单状态时恢复到之前状态。如生产中的工单在“暂停”或“冻结”后，人工恢复后可还原到“生产中”状态。</remarks>
    [SugarColumn(SqlParameterDbType = typeof(EnumToStringConvert))]
    public WoStatusEnum LastStatus { get; set; }

    public bool IsDeleted { get; set; }

    /// <summary>
    /// 更改单据状态。
    /// </summary>
    /// <param name="status"></param>
    public void ChangeStatus(WoStatusEnum status)
    {
        LastStatus = Status;
        Status = status;
    }

    /// <summary>
    /// 工单暂停
    /// </summary>
    public void HoldOn()
    {
        ChangeStatus(WoStatusEnum.OnHold);
    }

    /// <summary>
    /// 工单恢复
    /// </summary>
    public void Recover()
    {
        ChangeStatus(LastStatus);
    }

    /// <summary>
    /// 工单完工。
    /// </summary>
    public void Complete()
    {
        ChangeStatus(WoStatusEnum.Completed);
        ActualEndDate = DateTime.Now;
        Priority = 0;
    }
}
